<?php
/**
 * GeryEngine
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this release in the file LICENSE
 *
 * @copyright  Copyright (c) 2007 Arjen Brouwer
 * @license    New BSD License
 * @author     Arjen Brouwer
 */

abstract class TemplateBase {
	
	/**
	 * The GeryEngine
	 */
	protected $engine;
	
	/**
	 * The runtime services
	 *
	 * @var RuntimeServices
	 */
	protected $rs;
	
	/**
	 * The context
	 *
	 * @var IGeryContext
	 */
	protected $context;
	
	public function __construct(GeryEngine $engine) {
		$this->engine = $engine;
	}
	
	protected abstract function main(IGeryContext $context, RuntimeServices $rs);

	public function merge(GeryContext $context) {
		
		$rs = new RuntimeServices($this->engine);
		
		/*
		 * create an GeryHouseKeepingContext to carry the user Context down
		 * into the rendering engine.  Set the template name and render()
		 */
		try {
			return $this->main($context, $rs);
			
		// rethrow a GeryRuntimeExceptions
		} catch (Exception $e) {
			if ($e instanceof GeryException)
				throw $e;
				
			// handle unknown errors
			throw new GeryException("Unknown error: " . $e->getMessage());
		}
	}
	
	protected function setReference($context, $reference, $value) {
		if (! TemplateReferenceCompiler::setValue($context, $reference, $value)) {
			$this->rs->warning(
				sprintf("Could not set the value of reference %s", $reference[2])
			);
		}
	}
	
	protected function getReference(IGeryContext $context, RuntimeServices $rs, $reference, $returnSmurk = false) {

		$ret = TemplateReferenceCompiler::evaluateReference($context, $rs, $reference);
		
		if ($ret->evaluated) 
		{
			// pretty print arrays
			if ($returnSmurk) {
				return $this->dumpVariable($ret->value);
			} else {
				return $ret->value;
			}
		}
		
		// if we should return smurk and the reference is not silent
		else if ($returnSmurk && ! $reference[1]) 
		{
			// return the smurk of the reference
			return $reference[2];
		}
	}
	
	protected function dumpVariable($var, $nested = 0) {
		
		if ($nested == 10)
			return '*** RECURSE ***';
		
		switch (gettype($var)) {
			case 'array':
				$repr = array();
				
				foreach ($var as $key => $v) {
					$repr[] = $key . ': ' . $this->dumpVariable($v, $nested + 1);
				}
				
				return '[' . implode(', ', $repr) . ']';
			
			case 'boolean':
				return ($var) ? 'true' : 'false';
			
			default:
				return $var;
		}
	}
	
	protected function getTemplate($templateResource) {
		return $this->rs->getEngine()->getTemplate($templateResource);
	}
	
	protected function parseModifiers(RuntimeServices $rs, $value, $modifiers) {
		
		$ret = TemplateReferenceCompiler::getValue($rs, $value, $modifiers);
		
		if ($ret->evaluated) {
			return $ret->value;
		} else {
			return null;
		}	
	}
	
	/**
	 * Execute the parse directive
	 *
	 * @param string $resourceName
	 * @param Context $context
	 * @return string Output of the executed template
	 */
	protected function parseDirective($resourceName, RuntimeServices $rs, GeryTemplateContext $context, $line) {
		
		if ($resourceName == null) {
			$rs->log("#parse(): null argument", $line, LOG_LEVEL_ERROR);
		}
		
		try {
			$template = $rs->getTemplate($resourceName);
			return $template->main($context, $rs);	
			
		} catch (GeryResourceNotFoundException $e) {
			$rs->log(
				sprintf("#parse(): cannot find template '%s'", $resourceName), $line, LOG_LEVEL_ERROR);
				
		} catch (GeryException $e) {
			$rs->log(
				sprintf("#parse(): exception rendering template '%s': %s", $resourceName, $e->getMessage()), $line, LOG_LEVEL_ERROR);
		}
		
		return '';
	}
	
	public function includeDirective($resourceName, RuntimeServices $rs, GeryTemplateContext $context, $line) {
		if ($resourceName == null) {
			$rs->error("#include(): null argument", $line);
		}
		
		try {
			$resource = $rs->getResource($resourceName);
			return $resource->getData();
		} catch (GeryException $e) {
			$rs->log(
				sprintf("#include(): exception including file '%s': %s", $resourceName, $e->getMessage()), $line, LOG_LEVEL_ERROR);
		}
	}
}
?>